package es.unex.meigas.ww.core;

import java.awt.geom.Rectangle2D;
import java.awt.image.DataBuffer;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.io.File;

import javax.media.jai.PlanarImage;
import javax.media.jai.RasterFactory;

import org.geotools.coverage.CoverageFactoryFinder;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.coverage.grid.GridCoverageFactory;
import org.geotools.coverage.grid.io.AbstractGridCoverageWriter;
import org.geotools.gce.geotiff.GeoTiffWriter;
import org.geotools.geometry.Envelope2D;
import org.opengis.geometry.Envelope;
import org.opengis.referencing.crs.CoordinateReferenceSystem;

import es.unex.meigas.dataObjects.AbstractRasterLayer;
import es.unex.meigas.rasterWrappers.GridExtent;
import gw.layers.GridCoverageLayer;
import gw.util.ProjectionUtils;

public class WWRasterLayer extends AbstractRasterLayer {

	private static final double DEFAULT_NO_DATA_VALUE = -99999.;

	private CoordinateReferenceSystem m_CRS;
	private String m_sFilename;
	private String m_sName ="";
	private Raster m_Raster;
	private GridExtent m_LayerExtent;
	private double m_dNoDataValue;

	public void create(String name, String filename, GridExtent ge,
			int dataType, int numBands, Object crs) {

		if (!(crs instanceof CoordinateReferenceSystem)){
			crs = ProjectionUtils.getDefaultCRS();
		}

		if (dataType == DataBuffer.TYPE_DOUBLE){
			dataType = DataBuffer.TYPE_FLOAT;
		}

		m_Raster = RasterFactory.createBandedRaster(dataType,
								ge.getNX(), ge.getNY(), numBands, null);

		Envelope envelope = new Envelope2D((CoordinateReferenceSystem)crs,
											ge.getXMin(), ge.getYMin(),
											ge.getWidth(), ge.getHeight());
		GridCoverageFactory factory = CoverageFactoryFinder.getGridCoverageFactory(null);

		GridCoverage2D coverage = factory.create(name, (WritableRaster)m_Raster, envelope,
										null, null, null, null, null);
		m_BaseDataObject = new GridCoverageLayer(name, coverage);

		m_sName = name;
		m_sFilename = filename;
		m_LayerExtent = ge;
		m_dNoDataValue = DEFAULT_NO_DATA_VALUE;

	}

	public void create(GridCoverageLayer obj) {

		m_BaseDataObject = obj;
		GridCoverageLayer layer = (GridCoverageLayer)obj;
		GridCoverage2D gc = layer.getGridCoverage2D();
		m_CRS = gc.getCoordinateReferenceSystem();
		Envelope2D env = gc.getEnvelope2D();
		m_LayerExtent = new GridExtent();
		m_LayerExtent.setXRange(env.getMinX(), env.getMaxX());
		m_LayerExtent.setYRange(env.getMinY(), env.getMaxY());
		m_LayerExtent.setCellSize((env.getMaxX() - env.getMinX())
				/ (double)gc.getRenderedImage().getWidth());
		PlanarImage img = (PlanarImage) gc.geophysics(true).getRenderedImage();
		m_Raster = img.getAsBufferedImage().getRaster();
		m_sName = gc.getName().toString();

	}

	public void fitToGridExtent(GridExtent gridExtent) {

		WritableRaster raster = RasterFactory.createBandedRaster(getDataType(),
								gridExtent.getNX(), gridExtent.getNY(),
								getBandsCount(), null);

		Envelope envelope = new Envelope2D((CoordinateReferenceSystem)m_CRS,
								gridExtent.getXMin(), gridExtent.getYMin(),
								gridExtent.getWidth(), gridExtent.getHeight());
		GridCoverageFactory factory = CoverageFactoryFinder.getGridCoverageFactory(null);

		this.setWindowExtent(gridExtent);
		for (int x = 0; x < gridExtent.getNX(); x++) {
			for (int y = 0; y < gridExtent.getNY(); y++) {
				for (int i = 0; i < getBandsCount(); i++) {
					raster.setSample(x, y, i, this.getCellValueAsDouble(x, y, i));
				}
			}

		}
		m_Raster = raster;
		GridCoverage2D gc = factory.create(getName(), (WritableRaster)m_Raster, envelope,
										null, null, null, null, null);
		m_BaseDataObject = new GridCoverageLayer(this.m_sName, gc);

		System.gc();

	}

	public int getBandsCount() {

		if (m_BaseDataObject != null){
			GridCoverage2D gc = getGridCoverage2D();
			return gc.getNumSampleDimensions();
		}
		else{
			return 0;
		}

	}

	public double getCellValueInLayerCoords(int x, int y, int band) {

		if (m_Raster != null){
			return m_Raster.getSampleDouble(x, y, band);
		}
		else{
			return getNoDataValue();
		}

	}

	public int getDataType() {

		if (m_Raster != null){
			return m_Raster.getDataBuffer().getDataType();
		}
		else{
			return DataBuffer.TYPE_DOUBLE;
		}

	}

	public double getLayerCellSize() {

		if (m_LayerExtent != null){
			return m_LayerExtent.getCellSize();
		}
		else{
			return 0;
		}

	}

	public GridExtent getLayerGridExtent() {

		return m_LayerExtent;

	}

	public double getNoDataValue() {

		return m_dNoDataValue;

	}

	public void setCellValue(int x, int y, int band, double value) {

		if (isInWindow(x, y)){
			if (m_Raster instanceof WritableRaster){
				((WritableRaster)m_Raster).setSample(x, y, band, value);
			}
		}

	}

	public void setNoDataValue(double noDataValue) {

		m_dNoDataValue = noDataValue;

	}

	public Object getCRS() {

		return m_CRS;

	}

	public Rectangle2D getFullExtent() {

		if (m_BaseDataObject != null){
			GridCoverage2D gc = getGridCoverage2D();
			return new Envelope2D(gc.getEnvelope());
		}
		else{
			return null;
		}

	}

	public void open() {}

	public void close() {}

	public void postProcess() {

		try{
			AbstractGridCoverageWriter writer;
			writer = new GeoTiffWriter(new File(m_sFilename));
			GridCoverage2D gc = getGridCoverage2D();
			writer.write(gc.geophysics(true), null);
			writer.dispose();
		}catch (Exception e){
			e.printStackTrace();
		}

	}

	public String getFilename() {

		return m_sFilename;

	}

	public String getName() {

		return m_sName;

	}

	public void setName(String sName) {

		m_sName = sName;

	}

	private GridCoverage2D getGridCoverage2D(){

		return ((GridCoverageLayer)m_BaseDataObject).getGridCoverage2D();

	}


}
